/* Author: Hui Chen <usa.chen[at]gmail[dot]com>
*
* CluE or Cluster Engine, a parallel HTTPD running on clusters
* Published under GNU Public License version 3
*
*/

#include "clue.h"

int
main (int argc, char *argv[])
{
  int num_procs, myrank;
  MPI_Status status;
  int flag;

  MPI_Init (&argc, &argv);
  MPI_Comm_size (MPI_COMM_WORLD, &num_procs);
  MPI_Comm_rank (MPI_COMM_WORLD, &myrank);

  int pstatus[num_procs];	// 0=free, 1=busy
  int recv_status[num_procs];
  int tag1[num_procs];
  int tag2[num_procs];
  int tag3[num_procs];
  MPI_Request request[num_procs];
  int i, j, k, n;
  int isphp;
  int isfcgi;
  int hasdata;
  char php_path[] = "/usr/bin/php5-cgi";
  char fcgi_path[] = "/usr/local/bin/cgi-fcgi";
  char fcgi_name[] = "cgi-fcgi";
  char phpsocket[] = "/tmp/clue-sockets/clue-phpsocket";
  char socket_dir[] = "/tmp/clue-sockets/";
  char logfile_template[] = "/var/log/clue/access-%d.log";
  char logfile[256];
  sprintf (logfile, logfile_template, myrank);
  FILE *logfile_ptr;
  if (!(logfile_ptr = fopen (logfile, "w")))
  {
    printf ("Can't open logfile %s!\n", logfile);
    MPI_Abort (MPI_COMM_WORLD, 1);
  }
  mkdir (socket_dir, S_IWUSR | S_IRUSR | S_IXUSR);
  char mconnect[] = "-connect";
  struct _mpidata_from_root mpidata_from_root;
  struct _mpidata_to_root mpidata_to_root;
  char log[3000];
  int log_length = 0;
  int *log_len = &log_length;
  int url_status;
  int http_status;


  /* output pid of each process for debugging */
  {
    i = 0;
    char hostname[256];
    gethostname (hostname, sizeof (hostname));
    printf ("PID %d, Rank %d on %s ready for attach\n", getpid (), myrank, hostname);
    fflush (stdout);
  }


  for (i = 0; i < num_procs; i++)
  {
    pstatus[i] = 0;
    recv_status[i] = 0;
    tag1[i] = 10 + 3 * i - 2;
    tag2[i] = 10 + 3 * i - 1;
    tag3[i] = 10 + 3 * i;
  }

  int cnt, cnt0, cnt_s;
  int infd[2], outfd[2];
  int page_len = 0, page1_len = 0, page_404_len;
  int content_length;
  int list_dir, use_404;
  int sd, newSd[num_procs], server_port = 80;
  char server_port_c[20];
  socklen_t cliLen;
  struct sockaddr_in cliAddr, servAddr;
  char *pi, *pos;
  char script_filename[2560], filename2[2560], filename1[2560], filename[2560],
    sock_filename[2560], script_name[2560], http_cookie[2560], script_query[2560],
    script_query1[2560], line[MAX_MSG + 1], post_data[25600];
  char http_host[500];
  char Content_type[500];

  int script_query_len, post_data_len;
  char script_query_len_c[20];
  char post_data_len_c[20];
  char *message = malloc (MSG_LEN_LIMIT);;
  char *message_0 = message + sizeof (mpidata_from_root);
  int mymessage;
  char *root_dir = NULL;
  int support_cgi = 1;
  int http_method;		//0 GET, 1 POST, 2 PUT, 3 others
  char *myenviron[100];
  extern char **environ;
  environ = myenviron;

  if (argc == 1)
    print_usage (myrank);
  else
  {
    if ((argc - 1) % 2)
      print_usage (myrank);
    i = 1;
    while (i < argc)
    {
      if (argv[i][0] != '-')
	print_usage (myrank);
      switch (argv[i][1])
      {
      case 'p':
	if ((i + 1) >= argc)
	  print_usage (myrank);
	if (!(k = atoi (argv[i + 1])))
	  print_usage (myrank);
	server_port = k;
	break;
      case 'r':
	if ((i + 1) >= argc)
	  print_usage (myrank);
	root_dir = argv[i + 1];
	break;
      default:
	print_usage (myrank);
      }
      i += 2;
    }
    if (root_dir[0] != '/')
      print_usage (myrank);
    if (chdir (root_dir))
      printf ("Can't change to directory %s!\n", root_dir);
  }



  int content_type = 0;		//0 plain, 1 html, 2 jpeg, 3 png, 4 gif, 5 css, 6 bmp, 7 cgi
  char header_0[] =
    "HTTP/1.1 200 OK\r\nServer: clue\r\nContent-Type: text/plain\r\nConnection: close\r\n\r\n";
  char header_1[] =
    "HTTP/1.1 200 OK\r\nServer: clue\r\nContent-Type: text/html\r\nConnection: close\r\n\r\n";
  char header_2[] =
    "HTTP/1.1 200 OK\r\nServer: clue\r\nContent-Type: image/jpeg\r\nConnection: close\r\n\r\n";
  char header_3[] =
    "HTTP/1.1 200 OK\r\nServer: clue\r\nContent-Type: image/png\r\nConnection: close\r\n\r\n";
  char header_4[] =
    "HTTP/1.1 200 OK\r\nServer: clue\r\nContent-Type: image/gif\r\nConnection: close\r\n\r\n";
  char header_5[] =
    "HTTP/1.1 200 OK\r\nServer: clue\r\nContent-Type: text/css\r\nConnection: close\r\n\r\n";
  char header_6[] =
    "HTTP/1.1 200 OK\r\nServer: clue\r\nContent-Type: image/bmp\r\nConnection: close\r\n\r\n";
  char header_7[] = "HTTP/1.1 200 OK\r\nServer: clue\r\nConnection: close\r\n";

  char header_8[] =
    "HTTP/1.1 200 OK\r\nServer: clue\r\nContent-Type: image/x-icon\r\nConnection: close\r\n\r\n";
  char *header[] = { header_0, header_1, header_2, header_3, header_4, header_5,
    header_6,
    header_7, header_8
  };
  //header_cgi should not contain any Connection phase
  char header_cgi[] = "HTTP/1.1 200 OK\r\nServer: clue\r\n";
  char header_cgi_302[] = "HTTP/1.1 302 FOUND\r\nServer: clue\r\n";
  int header_len_cgi = strlen (header_cgi);
  int header_len_cgi_302 = strlen (header_cgi_302);
  char header_notfound[] =
    "HTTP/1.1 404 Not Found\r\nServer: clue\r\nContent-Type: text/html\r\nConnection: close\r\n\r\n";
  int header_len_404 = strlen (header_notfound);
  int header_len[9];
  for (i = 0; i < 9; i++)
    header_len[i] = strlen (header[i]);

  char *page_404 = malloc (DEFAULT_PAGE_LEN_LIMIT);
  char buildin_page_404[] =
    "HTTP/1.1 404 Not Found\r\nServer: clue\r\nContent-Type: text/html\r\nConnection: close\r\n\r\n<h2>404</h2>\nThe page cannot be found.";
  char *page, *page1;
  char *pages[num_procs];
  if (!myrank)
    for (i = 0; i < num_procs; i++)
    {
      pages[i] = malloc (PAGE_LEN_LIMIT);
      page = NULL;
      page1 = NULL;
    }
  else
  {
    page = malloc (PAGE_LEN_LIMIT);
    page1 = malloc (PAGE_LEN_LIMIT);
  }

  FILE *fp, *fp1;

  if (!(fp = fopen ("404.html", "r")))
  {
    free (page_404);
    page_404 = buildin_page_404;
    page_404_len = strlen (buildin_page_404);
  }
  else
  {
    memcpy (page_404, header_notfound, header_len_404);
    page_404_len =
      header_len_404 + fread (page_404 + header_len_404, 1, DEFAULT_PAGE_LEN_LIMIT, fp);
    if (page_404_len == 0 || page_404_len >= DEFAULT_PAGE_LEN_LIMIT)
    {
      printf ("Size of 404.html is illegal! sizeof(file) = %d\n", page_404_len);
      exit (1);
    }
    fclose (fp);
  }

  if (!myrank)
  {
    sd = socket (AF_INET, SOCK_STREAM, 0);
    if (sd < 0)
    {
      printf ("Can't open socket!\n");
      MPI_Abort (MPI_COMM_WORLD, 1);
    }

    setNonblocking (sd);
    servAddr.sin_family = AF_INET;
    servAddr.sin_addr.s_addr = htonl (INADDR_ANY);
    servAddr.sin_port = htons (server_port);
    if (bind (sd, (struct sockaddr *) &servAddr, sizeof (servAddr)) < 0)
    {
      printf ("Can't bind port %d!\n", server_port);
      MPI_Abort (MPI_COMM_WORLD, 1);
    }
    mpidata_from_root.s_port = server_port;


    struct ifaddrs *ifa = NULL, *ifp = NULL;

    if (getifaddrs (&ifp) < 0)
    {
      perror ("getifaddrs");
      return 1;
    }

    for (ifa = ifp; ifa; ifa = ifa->ifa_next)
    {
      if (ifa->ifa_addr->sa_family == AF_INET)
      {
	mpidata_from_root.s_addr.s_addr = ((struct sockaddr_in *) (ifa->ifa_addr))->sin_addr.s_addr;
	if ((mpidata_from_root.s_addr.s_addr & 255) != 127)
	  break;
      }

    }

    freeifaddrs (ifp);

    listen (sd, 1000);
    cliLen = sizeof (cliAddr);


    // trailing ending '/' in root_dir
    int i = strlen (root_dir) - 1;
    while (i >= 0 && root_dir[i] == '/')
      i--;
    root_dir[i + 1] = 0;

    sprintf (mpidata_from_root.cwd, "%s", root_dir);

  }
  else
  {
    sd = 0;
  }

  while (1)
  {
    if (!myrank)
    {
      i = 1;
      while (i < num_procs && pstatus[i])
	i++;
      if (i < num_procs)
      {
	newSd[i] = accept (sd, (struct sockaddr *) &cliAddr, &cliLen);
	if (newSd[i] >= 0)
	{
	  mpidata_from_root.c_addr.s_addr = cliAddr.sin_addr.s_addr;
	  mpidata_from_root.c_port = cliAddr.sin_port;
	  memcpy (message, &mpidata_from_root, sizeof (mpidata_from_root));
	  cnt = sizeof (mpidata_from_root);
	  hasdata = 0;
	  while ((cnt0 = sock_readline (newSd[i], message + cnt, MSG_LEN_LIMIT, 0)) > 0)
	  {

	    if (message[cnt] == 'C' && message[cnt + 7] == '-' && message[cnt + 8] == 'L')
	      hasdata = 1;
	    cnt += cnt0;
	    if (cnt0 == 2)
	      break;
	  }
	  if (hasdata)
	  {
	    cnt0 = sock_readline (newSd[i], message + cnt, MSG_LEN_LIMIT, 1);
	    cnt0--;
	    cnt += cnt0;
	  }

	  MPI_Send (message, cnt, MPI_CHAR, i, tag1[i], MPI_COMM_WORLD);

	  pstatus[i] = 1;
	  MPI_Irecv (pages[i], PAGE_LEN_LIMIT, MPI_CHAR, i, tag3[i], MPI_COMM_WORLD, &request[i]);
	}
      }

      for (i = 1; i < num_procs; i++)
      {
	if (pstatus[i] == 1)
	{
	  if (MPI_Test (&request[i], &flag, &status) != MPI_SUCCESS)
	  {
	    printf ("MPI_Test error!");
	  }
	  if (flag)
	  {
	    MPI_Get_count (&status, MPI_CHAR, &cnt);
	    memcpy (&mpidata_to_root, pages[i], sizeof (mpidata_to_root));
	    if ((cnt_s =
		 send (newSd[i], pages[i] + sizeof (mpidata_to_root),
		       cnt - sizeof (mpidata_to_root), 0)) != cnt - sizeof (mpidata_to_root))
	      printf ("socket send error!\n");
	    close (newSd[i]);
//          printheader (mpidata_to_root.log, &(mpidata_to_root.log_len), pages[i] + sizeof (struct _mpidata_to_root), "RETURN HEADER");
//          mpidata_to_root.log[mpidata_to_root.log_len] = 0;
//          (mpidata_to_root.log_len) += sprintf (mpidata_to_root.log + mpidata_to_root.log_len, "Data send to browser: %d\n", cnt_s);
	    if (mpidata_to_root.iscgi)
	    {
	      //printf ("===rank(%d)===\n", i);
	      //printlog (mpidata_to_root.log, &mpidata_to_root.log_len);
	    }
	    pstatus[i] = 0;
	  }
	}
      }
    }
    else
    {
      pos = message;
      content_length = 0;
      *filename = 0;
      *filename1 = 0;
      *filename2 = 0;
      *line = 0;
      fp1 = NULL;
      fp = NULL;
      infd[0] = 0;
      infd[1] = 0;
      outfd[0] = 0;
      outfd[1] = 0;
      list_dir = 0;
      use_404 = 1;
      content_type = 0;
      http_method = 3;
      script_query[0] = 0;
      script_query_len = 0;


      post_data[0] = 0;
      post_data_len = 0;

      isphp = 0;
      isfcgi = 0;
      *http_cookie = 0;
      *http_host = 0;
//      log = mpidata_to_root.log;
//      log_len = (&mpidata_to_root.log_len);
      (*log) = 0;
      *log_len = 0;
      *page = 0;
      page_len = 0;
      *Content_type = 0;

      mpidata_to_root.iscgi = 0;

      MPI_Recv (message, MSG_LEN_LIMIT, MPI_CHAR, 0, tag1[myrank], MPI_COMM_WORLD, &status);
      MPI_Get_count (&status, MPI_CHAR, &cnt);


      cnt -= sizeof (mpidata_from_root);
      memcpy (&mpidata_from_root, message, sizeof (mpidata_from_root));

      message_0 = message + sizeof (mpidata_from_root);

      printrequest (log, log_len, message_0, cnt, "REQUEST RAW DATA");

      mymessage = 0;
      while ((n = readline (message_0, &mymessage, cnt, line, MAX_MSG)) > 1)
      {
	if (line[n - 1] == '\r')
	{
	  n = n - 1;
	  line[n] = 0;
	}
	if (n == 0)
	  break;

	switch (*line)
	{
	case 'G':
	  if (line[1] == 'E')
	    http_method = 0;
	case 'P':
	  if (line[1] == 'O')
	    http_method = 1;
	  else if (line[1] == 'U')
	    http_method = 2;

	  for (pi = line + (http_method == 1 ? 5 : 4); (*pi) == '.' && (*pi) == '/'; pi++);
	  pi++;
	  script_name[0] = '/';
	  for (i = 0; pi[i] != ' ' && pi[i] != '?'; i++)
	  {
	    filename[i] = pi[i];
	    if (pi[i] != '/')
	      filename1[i] = pi[i];
	    else
	      filename1[i] = '_';

	    script_name[i + 1] = pi[i];
	  }


	  if (pi[i] == '?')
	  {
	    for (k = i + 1; pi[k] != ' '; k += 1)
	    {
	      script_query[script_query_len] = pi[k];
	      script_query_len++;
	    }
	    script_query[script_query_len] = 0;
	  }

	  /*trailing ending redundent '/'
	     pi[0] is the first none '/' in request URL
	   */
	  i--;
	  while (pi[i] == '/' && i >= 0)
	    i--;
	  i++;
	  /* now pi[i] is the last none '/' in request URL(before '?')
	     so do filename[i], filename1[i] and script_name[i+1]
	     however, filename1[i] and script_name[i+1] will not be used since
	     the requested url is a folder
	   */
	  if (pi[i] == '/')
	    i++;
	  filename[i] = 0;
	  filename1[i] = 0;
	  script_name[i + 1] = 0;

	  if (!i)
	  {
	    // root dir
	    if (urlrewrite (".", filename2) == URL_FOLDER)
	    {
	      list_dir = 1;
	      use_404 = 0;

	      listdir (page, &page_len, ".");
	      break;

	    }
	    else
	    {
	      cnt0 = strlen (filename2);
	      memcpy (filename, filename2, cnt0);
	      memcpy (script_name + 1, filename2, cnt0);
	      filename[cnt0] = 0;
	      script_name[cnt0 + 1] = 0;
	      i = cnt0;
	    }
	  }
	  else
	  {
	    url_status = urlrewrite (filename, filename2);

	    if (url_status == URL_FOLDER_REDIRECT)
	    {
	      list_dir = 1;
	      use_404 = 0;
	      folder_redirect (page, &page_len, filename);
	      break;
	    }
	    else if (url_status == URL_FOLDER)
	    {
	      list_dir = 1;
	      use_404 = 0;
	      listdir (page, &page_len, filename);
	      break;

	    }
	    else
	    {
	      cnt0 = strlen (filename2);
	      memcpy (filename, filename2, cnt0);
	      memcpy (script_name + 1, filename2, cnt0);
	      filename[cnt0] = 0;
	      script_name[cnt0 + 1] = 0;
	      i = cnt0;

	    }

	  }

	  for (j = i - 1; j >= 0 && filename[j] != '/' && filename[j] != '.'; j--);
	  if (filename[j] == '.')
	  {
	    j++;
	    if (filename[j] == 'h' && filename[j + 1] == 't'
		&& filename[j + 2] == 'm' && filename[j + 3] == 'l')
	      content_type = 1;
	    else if (filename[j] == 'H'
		     && filename[j + 1] == 'T' && filename[j + 2] == 'M' && filename[j + 3] == 'L')
	      content_type = 1;
	    else if (filename[j] == 'j' && filename[j + 1] == 'p' && filename[j + 2] == 'g')
	      content_type = 2;
	    else if (filename[j] == 'J' && filename[j + 1] == 'P' && filename[j + 2] == 'G')
	      content_type = 2;
	    else if (filename[j] == 'j'
		     && filename[j + 1] == 'p' && filename[j + 2] == 'e' && filename[j + 3] == 'g')
	      content_type = 2;
	    else if (filename[j] == 'J'
		     && filename[j + 1] == 'P' && filename[j + 2] == 'E' && filename[j + 3] == 'G')
	      content_type = 2;
	    else if (filename[j] == 'p' && filename[j + 1] == 'n' && filename[j + 2] == 'g')
	      content_type = 3;
	    else if (filename[j] == 'P' && filename[j + 1] == 'N' && filename[j + 2] == 'G')
	      content_type = 3;
	    else if (filename[j] == 'g' && filename[j + 1] == 'i' && filename[j + 2] == 'f')
	      content_type = 4;
	    else if (filename[j] == 'G' && filename[j + 1] == 'I' && filename[j + 2] == 'F')
	      content_type = 4;
	    else if (filename[j] == 'c' && filename[j + 1] == 's' && filename[j + 2] == 's')
	      content_type = 5;
	    else if (filename[j] == 'C' && filename[j + 1] == 'S' && filename[j + 2] == 'S')
	      content_type = 5;
	    else if (filename[j] == 'b' && filename[j + 1] == 'm' && filename[j + 2] == 'p')
	      content_type = 6;
	    else if (filename[j] == 'B' && filename[j + 1] == 'M' && filename[j + 2] == 'P')
	      content_type = 6;
	    else if (filename[j] == 'c' && filename[j + 1] == 'g' && filename[j + 2] == 'i')
	      content_type = 7;
	    else if (filename[j] == 'C' && filename[j + 1] == 'G' && filename[j + 2] == 'I')
	      content_type = 7;
	    else if (filename[j] == 'p' && filename[j + 1] == 'h' && filename[j + 2] == 'p')
	    {
	      isphp = 1;
	      content_type = 7;
	    }
	    else if (filename[j] == 'P' && filename[j + 1] == 'H' && filename[j + 2] == 'P')
	    {
	      isphp = 1;
	      content_type = 7;
	    }
	    else if (filename[j] == 'f'
		     && filename[j + 1] == 'c' && filename[j + 2] == 'g' && filename[j + 3] == 'i')
	    {
	      isfcgi = 1;
	      content_type = 7;
	    }
	    else if (filename[j] == 'F'
		     && filename[j + 1] == 'C' && filename[j + 2] == 'G' && filename[j + 3] == 'I')
	    {
	      isfcgi = 1;
	      content_type = 7;
	    }
	    else if (filename[j] == 'i' && filename[j + 1] == 'c' && filename[j + 2] == 'o')
	      content_type = 8;
	    else if (filename[j] == 'I' && filename[j + 1] == 'C' && filename[j + 2] == 'O')
	      content_type = 8;

	  }
	  list_dir = 0;
	  use_404 = 0;

	  break;
	default:
	  break;
	}
	if (http_method == 1 && *line == 'C' && line[7] == '-' && line[8] == 'L')
	  content_length = atoi (line + 16);
	if (content_type == 7 && *line == 'C' && line[2] == 'o' && line[3] == 'k')
	{
	  memcpy (http_cookie, &line[8], n - 8);
	  http_cookie[n - 8] = 0;
	}
	if (content_type == 7 && *line == 'H' && line[1] == 'o' && line[3] == 't')
	{
	  memcpy (http_host, &line[6], n - 6);
	  http_host[n - 6] = 0;
	}
	if (content_type == 7 && *line == 'C' && line[1] == 'o' && line[8] == 'T')
	{
	  memcpy (Content_type, &line[14], n - 14);
	  Content_type[n - 14] = 0;
	}

      }

      if (http_method == 1 && content_length)
      {
	n = cnt - mymessage;
//readline (message_0, &mymessage, cnt, line, MAX_MSG);

	if (n > 0)
	{
	  //      n--;
	  if (n != content_length)
	  {
	    memcpy (page, &mpidata_to_root, sizeof (struct _mpidata_to_root));
	    memcpy (page + sizeof (struct _mpidata_to_root), page_404, page_404_len);
	    MPI_Send (page,
		      page_404_len +
		      sizeof (struct _mpidata_to_root), MPI_CHAR, 0, tag3[myrank], MPI_COMM_WORLD);
	    continue;
	  }
	  for (i = 0; i < n; i += 1)
	  {
	    post_data[post_data_len] = message_0[i + mymessage];
	    post_data_len++;
	  }
	  post_data[post_data_len] = 0;
	}
      }


      if (!list_dir && http_method < 3)
      {
	if (support_cgi && content_type == 7)	//CGI
	{
	  mpidata_to_root.iscgi = 1;
	  if (!(fp1 = fopen (filename, "r")) || pipe (outfd) < 0 || pipe (infd) < 0)
	  {
	    if (!fp1)
	      printf ("fopen failed!\n");
	    else
	    {
	      printf ("pipe open failed!\n");
	      fclose (fp1);
	    }
	    list_dir = 0;
	    use_404 = 1;
	  }
	  else
	  {
	    fclose (fp1);

	    sprintf (script_query_len_c, "%d", script_query_len);
	    sprintf (script_filename, "%s/%s", mpidata_from_root.cwd, filename);


	    mysetenv (log, log_len, "SERVER_SOFTWARE", "clue", 1);
	    mysetenv (log, log_len, "GATEWAY_INTERFACE", "CGI/1.1", 1);
	    mysetenv (log, log_len, "SERVER_PROTOCOL", "HTTP/1.1", 1);
	    mysetenv (log, log_len, "SERVER_SIGNATURE", "", 1);

	    sprintf (post_data_len_c, "%d", post_data_len);

	    /* only setenv CONTENT_LENGTH when is a php page */
	    if (post_data_len && isphp)
	      mysetenv (log, log_len, "CONTENT_LENGTH", post_data_len_c, 1);
	    else
	      unsetenv ("CONTENT_LENGTH");


	    /* distinguish between isphp and not php page */
	    if (isphp)
	    {
	      if (script_query_len)
		mysetenv (log, log_len, "QUERY_STRING", script_query, 1);
	      else
		unsetenv ("QUERY_STRING");
	    }
	    else
	    {
	      if (!post_data_len && !script_query_len)
		unsetenv ("QUERY_STRING");
	      else if (post_data_len && script_query_len)
	      {
		sprintf (script_query1, "%s&%s", post_data, script_query);
		mysetenv (log, log_len, "QUERY_STRING", script_query1, 1);
	      }
	      else if (post_data_len)
	      {
		mysetenv (log, log_len, "QUERY_STRING", post_data, 1);
	      }
	      else
	      {
		mysetenv (log, log_len, "QUERY_STRING", script_query, 1);
	      }
	    }

	    /* when http_cookie = '', unsetenv HTTP_COOKIE */
	    if (*http_cookie)
	      mysetenv (log, log_len, "HTTP_COOKIE", http_cookie, 1);
	    else
	      unsetenv ("HTTP_COOKIE");
	    mysetenv (log, log_len, "REQUEST_METHOD",
		      http_method == 0 ? "GET" : (http_method == 1 ? "POST" : "PUT"), 1);
	    mysetenv (log, log_len, "REQUEST_URI", script_name, 1);
	    mysetenv (log, log_len, "SCRIPT_NAME", script_name, 1);
	    mysetenv (log, log_len, "REMOTE_ADDR", inet_ntoa (mpidata_from_root.c_addr), 1);
	    sprintf (server_port_c, "%d", mpidata_from_root.c_port);

	    mysetenv (log, log_len, "REMOTE_PORT", server_port_c, 1);
	    mysetenv (log, log_len, "SERVER_ADDR", inet_ntoa (mpidata_from_root.s_addr), 1);
	    sprintf (server_port_c, "%d", mpidata_from_root.s_port);
	    mysetenv (log, log_len, "SERVER_PORT", server_port_c, 1);
	    mysetenv (log, log_len, "SERVER_NAME", inet_ntoa (mpidata_from_root.s_addr), 1);
	    mysetenv (log, log_len, "SCRIPT_FILENAME", script_filename, 1);
	    mysetenv (log, log_len, "DOCUMENT_ROOT", mpidata_from_root.cwd, 1);

			/* setenv CONTENT_TYPE only when it's not empty */
			if (*Content_type)
	    mysetenv (log, log_len, "CONTENT_TYPE", Content_type, 1);
			else
			unsetenv("CONTENT_TYPE");
	    mysetenv (log, log_len, "HTTP_HOST", http_host, 1);


	    if (!fork ())
	    {

	      if (post_data_len && isphp)
	      {
		close (0);
		dup2 (outfd[0], 0);
		close (1);
		dup2 (infd[1], 1);
		close (outfd[1]);
		close (infd[0]);
//                                                              close (outfd[0]);
//                                                              close (infd[1]);
	      }
	      else
	      {
		close (1);
		dup2 (infd[1], 1);
		close (infd[0]);
		close (infd[1]);
//                                                              close(outfd[0]);
//                                                              close(outfd[1]);
	      }

	      if (isphp)
	      {
		if (execl (fcgi_path, fcgi_name, mconnect, phpsocket, php_path, NULL))
		  //if (execl (php_path, php_path, filename, NULL))
		  exit (0);
	      }
	      else if (isfcgi)
	      {
		sprintf (sock_filename, "%s%s", socket_dir, filename1);
		if (execl (fcgi_path, fcgi_name, mconnect, sock_filename, filename, NULL))
		  exit (0);
	      }
	      else		//normal CGI
	      {
		if (execl (filename, filename, NULL))
		  exit (0);
	      }
	    }
	    if (isphp && post_data_len)
	    {
	      close (outfd[0]);
	      //printf ("Writing to child process\n");
	      cnt = write (outfd[1], post_data, post_data_len);
	      if (cnt != post_data_len)
		printf ("cnt!=post_data_len\n");
	      close (outfd[1]);
	      //printf ("Write to child process finished\n");
	    }
	    else
	    {
	      close (outfd[0]);
	      close (outfd[1]);
	    }
	    close (infd[1]);

	    // read data from child process
	    page_len = read (infd[0], page1, PAGE_LEN_LIMIT);

	    //find http status  
	    i = 0;
	    n = readline (page1, &i, page_len, line, MAX_MSG);
	    line[n] = 0;
	    if (line[0] == 'S' && line[1] == 't' && line[2] == 'a')
	    {
	      http_status = atoi (&line[8]);
	    }
	    else
	    {
	      http_status = 200;
	    }

	    // attach different headers according to status returned by PHP
	    switch (http_status)
	    {
	    case 302:
	      memcpy (page, header_cgi_302, header_len_cgi_302);
	      memcpy (page + header_len_cgi_302, page1, page_len);
	      page_len += header_len_cgi_302;
	      break;
	    default:
	      memcpy (page, header_cgi, header_len_cgi);
	      memcpy (page + header_len_cgi, page1, page_len);
	      page_len += header_len_cgi;
	      break;
	    }

	    // Append log
	    (*log_len) +=
	      sprintf (log + (*log_len), "Data length from child process: %d\n", page_len);

	    list_dir = 0;
	    use_404 = 0;
	    close (infd[0]);
	  }
	}
	else
	{
	  if (!(fp = fopen (filename, "r")))
	  {
//          printf ("fopen failed!\n");
	    list_dir = 0;
	    use_404 = 1;
	  }
	  else
	  {

	    memcpy (page, header[content_type], header_len[content_type]);
	    page_len = fread (page + header_len[content_type], 1, PAGE_LEN_LIMIT, fp);
	    if (page_len == 0 && !listdir (page, &page_len, filename))
	    {

	      list_dir = 1;
	      use_404 = 0;
	    }
	    else if (page_len == 0 || page_len == PAGE_LEN_LIMIT)
	    {
	      list_dir = 0;
	      use_404 = 1;
	    }
	    else
	    {
	      list_dir = 0;
	      use_404 = 0;
	      page_len += header_len[content_type];
	      fclose (fp);
	    }

	    (*log_len) += sprintf (log + (*log_len), "Data length from file: %d\n", page_len);
	  }
	}
      }

      /* output to logfile */
      if (mpidata_to_root.iscgi)
      {
	fprintf (logfile_ptr, "===rank(%d)===\n", myrank);
	printlog (logfile_ptr, log, log_len);
	/* flush before going on */
	fflush (logfile_ptr);
      }


      memcpy (page1, &mpidata_to_root, sizeof (mpidata_to_root));
      page1_len = sizeof (mpidata_to_root);

      if (use_404)
      {
	memcpy (page1 + sizeof (mpidata_to_root), page_404, page_404_len);
	page1_len += page_404_len;
      }
      else
      {
	memcpy (page1 + sizeof (mpidata_to_root), page, page_len);
	page1_len += page_len;
      }

      MPI_Send (page1, page1_len, MPI_CHAR, 0, tag3[myrank], MPI_COMM_WORLD);

    }
  }
  free (message);
  free (page);
  free (page_404);
  close (sd);
  MPI_Finalize ();
}



inline void
print_usage (int myrank)
{
  if (!myrank)
  {
    printf ("Usage: \n\tclue -p port -r wwwroot\nExample: \n\tclue -p 80 -r /var/www/clue\n");
  }
  exit (0);
}
